using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;

namespace MyEditor
{
    struct Point
    {
        public int x;
        public int y;
        public int color;
        public int group;

        public Point(int x, int y, int c, int g)
        {
            this.x = x;
            this.y = y;
            this.color = c;
            this.group = g;
        }

        public void setGroup(int g)
        {
            this.group = g;
        }



    }
    class Kmeans
    {
        Boolean Moved;
        Random ran = new Random();
        int k;
        int[] group;
        Point[] pixels;
        Bitmap pic;

        public Kmeans(Bitmap pic,int k)
        {
            group = new int[k];
            this.k = k;
            this.pic = new Bitmap(pic);
            pixels = new Point[pic.Width * pic.Height];
            unsafe
            {
                BitmapData data = pic.LockBits
                    (new Rectangle(0, 0, pic.Width, pic.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                byte* imgPtr = (byte*)(data.Scan0);


                for (int i = 0; i < data.Height; i++)
                {
                    for (int j = 0; j < data.Width; j++)
                    {
                        int c = (int)Color.FromArgb(0,imgPtr[2], imgPtr[1], imgPtr[0]).ToArgb();

                        pixels[pic.Width * i + j].x = j;
                        pixels[pic.Width * i + j].y = i;
                        pixels[pic.Width * i + j].color = Math.Abs(c);
                        pixels[pic.Width * i + j].group = -1;


                        imgPtr = imgPtr + 3;
                    }
                    imgPtr += data.Stride - data.Width * 3;
                }
                pic.UnlockBits(data);
            }
        }

        public void DokMeans()
        {
            int[] countOfeachgroup = new int[k];
            ulong[] amontOfeachgroup = new ulong[k];
            for (int i = 0; i < k; i++)
            {
                countOfeachgroup[i] = 0;
                amontOfeachgroup[i] = 0;

            }
            Random ran2 = new Random();
            int r = ran2.Next(pic.Height * pic.Width);
            group[0] = pixels[r].color;
            pixels[r].setGroup(0);

            for (int i = 1; i < k; i++)
            {

                
                bool haveit = true;
                while (haveit)
                {
                    r = ran2.Next(pic.Height * pic.Width);
                    int n;
                    for ( n= 0; n <i; n++)
                    {
                        if (pixels[r].color == group[n])
                            break;
                    }
                    if (n==i)
                        haveit = false;
                   
                }
                group[i] = pixels[r].color;
                pixels[r].setGroup(i);
            }
            for (int n = 0; n < pic.Width * pic.Height; n++)
            {
                if (pixels[n].group != -1)
                    continue;
                ulong dist;
                dist = ((ulong)(pixels[n].color - group[0]) * (ulong)(pixels[n].color - group[0]));
                pixels[n].setGroup(0);
                for (int i = 1; i < k; i++)
                {
                    if (((ulong)(pixels[n].color - group[i]) * (ulong)(pixels[n].color - group[i])) < dist)
                    {

                        pixels[n].setGroup(i);
                        dist = ((ulong)(pixels[n].color - group[i]) * (ulong)(pixels[n].color - group[i]));

                    }
                }


            }

            while (true)
            {
                Moved = false;


                foreach (Point p in pixels)
                {
                    countOfeachgroup[p.group]++;
                    amontOfeachgroup[p.group] += (ulong)p.color;
                }

                for (int i = 0; i < k; i++)
                {
                    if (countOfeachgroup[i] != 0)
                        group[i] = (int)(amontOfeachgroup[i] / (ulong)countOfeachgroup[i]);
                }
                /*for (int i = 0; i < k; i++)
                {
                    ulong sum = 0;
                    int count = 0;
                    foreach (Point p in pixels)
                    {

                        if (p.group == i)
                        {
                            count++;
                            sum = sum + (ulong)p.color;
                            if (p.color<0)
                            {

                            }

                        }

                    }
                    if (count!=0)
                        group[i] = (int)(sum / (ulong)count);
                }*/
                /*
                for (int i = 0; i < 64; i++)
                    if (countOfeachgroup[i] != 0)
                    {
                        group[i] = (int)amontOfeachgroup[i] / countOfeachgroup[i];
                    }
                    else
                    {
                        group[i] = 0;
                    }*/
                
                for (int j = 0; j < pic.Width * pic.Height; j++)
                {

                    ulong dist = (ulong)(pixels[j].color - group[pixels[j].group]) * (ulong)(pixels[j].color - group[pixels[j].group]);
                    for (int i = 0; i < k; i++)
                    {
                        ulong tempDis = (ulong)(pixels[j].color - group[i]) * (ulong)(pixels[j].color - group[i]); ;
                        if (tempDis < dist)
                        {

                            pixels[j].group = i;
                            Moved = true;
                        }
                    }

                }

                if (Moved == false)
                    break;
            }

        }



        public long checkit()
        {
            List<List<Point>> g = new List<List<Point>>();
            for (int i = 0; i < k; i++)
            {
                List<Point> t = new List<Point>();
                g.Add(t);
            }
            foreach (Point p in pixels)
            {
                g[p.group].Add(p);
            }
            long[] s = new long[k];
            for (int i = 0; i < k; i++)
            {
                for (int j = 0; j < g[i].Count; j++)
                {
                    for (int n = j + 1; n < g[i].Count; n++)
                    {
                        s[i] = s[i] + (long)(g[i][j].color - g[i][n].color) * (long)(g[i][j].color - g[i][n].color);
                    }
                }
            }
            long sum = 0;
            for (int i = 0; i < k; i++)
            {
                sum = sum + s[i];
            }
            return sum;
        }

        public byte[,] getResult2()
        {
            Point[] SortedPixels = new Point[pixels.Length];
            int[] sortedGroup = new int[k];
            int[] swap = new int[k];
            for (int i = 0; i < k; i++)
                sortedGroup[i] = group[i];
            try
            {
                Array.Sort(sortedGroup);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            for (int i = 0; i < k; i++)
            {
                int t = sortedGroup[i];
                int j;
                for (j = 0; j < k; j++)
                {
                    if (t == group[j])
                        break;
                }

                swap[j] = i;

            }



            byte[,] temp = new byte[pic.Width, pic.Height];
            foreach (Point p in pixels)
            {
                temp[p.x, p.y] = (byte)swap[p.group];

            }

            return temp;

        }

        public Bitmap getResult()
        {


            Point[] SortedPixels = new Point[pixels.Length];
            int[] sortedGroup = new int[k];
            int[] swap = new int[k];
            for (int i = 0; i < k; i++)
                sortedGroup[i] = group[i];
            try
            {
                Array.Sort(sortedGroup);
            }
            catch(Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            for (int i = 0; i < k; i++)
            {
                int t = sortedGroup[i];
                int j;
                for ( j= 0; j < k; j++)
                {
                    if (t == group[j])
                        break;
                }

                swap[j] = i;

            }
 
            byte[,] temp = new byte[pic.Width, pic.Height];
            foreach (Point p in pixels)
            {
                temp[p.x, p.y] = (byte)swap[p.group];

            }
            unsafe
            {
                BitmapData data = pic.LockBits
                    (new Rectangle(0, 0, pic.Width, pic.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                byte* imgPtr = (byte*)(data.Scan0);


                for (int i = 0; i < data.Height; i++)
                {
                    for (int j = 0; j < data.Width; j++)
                    {
                        imgPtr[0] = imgPtr[1] = imgPtr[2] = temp[j, i];
                        imgPtr = imgPtr + 3;
                    }
                    imgPtr += data.Stride - data.Width * 3;
                }
                pic.UnlockBits(data);
            }
            return pic;

        }
    }
}
